package com.imy.virtual.client.core;

import android.content.Context;
import android.os.Build;
import android.os.IInterface;
import android.util.Log;

import com.imy.virtual.client.hook.base.LogInvocation;
import com.imy.virtual.client.hook.base.MethodInvocationProxy;
import com.imy.virtual.client.hook.base.MethodInvocationStub;
import com.imy.virtual.client.hook.delegate.AppInstrumentation;
import com.imy.virtual.client.hook.mount.MountServiceStub;
import com.imy.virtual.client.hook.proxies.account.AccountManagerStub;
import com.imy.virtual.client.hook.proxies.alarm.AlarmManagerStub;
import com.imy.virtual.client.hook.proxies.am.ActivityManagerStub;
import com.imy.virtual.client.hook.proxies.am.HCallbackStub;
import com.imy.virtual.client.hook.proxies.appops.AppOpsManagerStub;
import com.imy.virtual.client.hook.proxies.appwidget.AppWidgetManagerStub;
import com.imy.virtual.client.hook.proxies.atm.ActivityTaskManagerStub;
import com.imy.virtual.client.hook.proxies.audio.AudioManagerStub;
import com.imy.virtual.client.hook.proxies.backup.BackupManagerStub;
import com.imy.virtual.client.hook.proxies.bluetooth.BluetoothStub;
import com.imy.virtual.client.hook.proxies.clipboard.ClipBoardStub;
import com.imy.virtual.client.hook.proxies.connectivity.ConnectivityStub;
import com.imy.virtual.client.hook.proxies.content.ContentServiceStub;
import com.imy.virtual.client.hook.proxies.context_hub.ContextHubServiceStub;
import com.imy.virtual.client.hook.proxies.devicepolicy.DevicePolicyManagerStub;
import com.imy.virtual.client.hook.proxies.display.DisplayStub;
import com.imy.virtual.client.hook.proxies.dropbox.DropBoxManagerStub;
import com.imy.virtual.client.hook.proxies.fingerprint.FingerprintManagerStub;
import com.imy.virtual.client.hook.proxies.graphics.GraphicsStatsStub;
import com.imy.virtual.client.hook.proxies.imms.MmsStub;
import com.imy.virtual.client.hook.proxies.input.InputMethodManagerStub;
import com.imy.virtual.client.hook.proxies.isms.ISmsStub;
import com.imy.virtual.client.hook.proxies.isub.ISubStub;
import com.imy.virtual.client.hook.proxies.job.JobServiceStub;
import com.imy.virtual.client.hook.proxies.libcore.LibCoreStub;
import com.imy.virtual.client.hook.proxies.location.LocationManagerStub;
import com.imy.virtual.client.hook.proxies.media.router.MediaRouterServiceStub;
import com.imy.virtual.client.hook.proxies.media.session.SessionManagerStub;
import com.imy.virtual.client.hook.proxies.network.NetworkManagementStub;
import com.imy.virtual.client.hook.proxies.notification.NotificationManagerStub;
import com.imy.virtual.client.hook.proxies.persistent_data_block.PersistentDataBlockServiceStub;
import com.imy.virtual.client.hook.proxies.phonesubinfo.PhoneSubInfoStub;
import com.imy.virtual.client.hook.proxies.pm.PackageManagerStub;
import com.imy.virtual.client.hook.proxies.power.PowerManagerStub;
import com.imy.virtual.client.hook.proxies.restriction.RestrictionStub;
import com.imy.virtual.client.hook.proxies.search.SearchManagerStub;
import com.imy.virtual.client.hook.proxies.shortcut.ShortcutServiceStub;
import com.imy.virtual.client.hook.proxies.telephony.TelephonyRegistryStub;
import com.imy.virtual.client.hook.proxies.telephony.TelephonyStub;
import com.imy.virtual.client.hook.proxies.usage.UsageStatsManagerStub;
import com.imy.virtual.client.hook.proxies.user.UserManagerStub;
import com.imy.virtual.client.hook.proxies.vibrator.VibratorStub;
import com.imy.virtual.client.hook.proxies.view.AutoFillManagerStub;
import com.imy.virtual.client.hook.proxies.wifi.WifiManagerStub;
import com.imy.virtual.client.hook.proxies.wifi_scanner.WifiScannerStub;
import com.imy.virtual.client.hook.proxies.window.WindowManagerStub;
import com.imy.virtual.client.hook.utils.MethodParameterUtils;
import com.imy.virtual.client.interfaces.IInjector;
import com.imy.virtual.helper.utils.So64;
import com.imy.virtual.helper.utils.VLog;
import com.imy.virtual.tools.AndroidVersionConstant;
import com.imy.virtual.tools.EmulatorDetector;

import java.util.HashMap;
import java.util.Map;

import mirror.MethodParams;
import mirror.RefStaticMethod;
import mirror.android.app.ActivityManager;
import mirror.android.app.ActivityManagerNative;
import mirror.android.app.IActivityManager;

import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR2;
import static android.os.Build.VERSION_CODES.KITKAT;
import static android.os.Build.VERSION_CODES.LOLLIPOP;
import static android.os.Build.VERSION_CODES.LOLLIPOP_MR1;
import static android.os.Build.VERSION_CODES.M;
import static android.os.Build.VERSION_CODES.N;

public final class InvocationStubManager {
  private static InvocationStubManager sInstance = new InvocationStubManager();
  private static boolean sInit;
  private Map<Class<?>, IInjector> mInjectors = new HashMap<>(13);

  private InvocationStubManager() {
  }

  public static InvocationStubManager getInstance() {
    return sInstance;
  }

  void injectAll() throws Throwable {
    for (IInjector injector : mInjectors.values()) {
      injector.inject();
    }
    VLog.i("这里的 AppInstrumentation 注入是比较重要的一环，他是生成以及 控制一个应用的关键组件，他会new activity ，也会new application");
    addInjector(AppInstrumentation.getDefault());
    if (VirtualCore.get().isServerProcess()) {
      VLog.i(" ====》  VA 框架服务 注入 完成");
    }
    if (VirtualCore.get().isVAppProcess()) {
      VLog.i("AppInstrumentation"," ====》  虚拟应用 framework 注入 完成："+AppInstrumentation.getDefault().isEnvBad());
      //
    }
  }

  public boolean isInit() {
    return sInit;
  }

  public void init(Context context) throws Throwable {
    if (isInit()) {
      throw new IllegalStateException("InvocationStubManager Has been initialized.");
    }
    injectInternal(context);
    sInit = true;
  }

  private void injectInternal(Context context) throws Throwable {
    if (VirtualCore.get().isMainProcess()) {
      So64.fix64bitSoError();
      return;
    }
    if (VirtualCore.get().isServerProcess()) {

      addInjector(ActivityManagerStub.injectStub());
      addInjector(new PackageManagerStub());

      VLog.i(" ====》  VA 框架服务 内部初始化 完成");
      return;
    }
    if (VirtualCore.get().isVAppProcess()) {
      //addInjector(new LibCoreStub()); //注入LibCore 会造成某些游戏崩溃 另外这快的作用还不清楚
      addInjector(ActivityManagerStub.injectStub());
      if (Build.VERSION.SDK_INT >= AndroidVersionConstant.Q_10) {
        addInjector(new ActivityTaskManagerStub()); //兼容android10启动Activity
      }
      addInjector(new PackageManagerStub());
      addInjector(HCallbackStub.getDefault());
      addInjector(new ISmsStub());
      addInjector(new ISubStub());
      addInjector(new DropBoxManagerStub());
      addInjector(new NotificationManagerStub());
      addInjector(new LocationManagerStub());
      addInjector(new WindowManagerStub());
      addInjector(new ClipBoardStub());
      addInjector(new MountServiceStub());

      addInjector(new BackupManagerStub());
      addInjector(new TelephonyStub());
      addInjector(new TelephonyRegistryStub());
      addInjector(new PhoneSubInfoStub()); //修复调用PhoneStubInfo错误问题
      addInjector(new PowerManagerStub());
      addInjector(new AppWidgetManagerStub());
      addInjector(new AccountManagerStub());
      addInjector(new AudioManagerStub());
      addInjector(new SearchManagerStub());
      addInjector(new ContentServiceStub());
      addInjector(new ConnectivityStub());
      addInjector(new VibratorStub());
      addInjector(new WifiManagerStub());
      if (!EmulatorDetector.isEmulator(context)) {
        addInjector(new BluetoothStub());
      }
      addInjector(new ContextHubServiceStub());
      addInjector(new UserManagerStub());
      addInjector(new DisplayStub());
      if (Build.VERSION.SDK_INT >= LOLLIPOP) {
        if (!EmulatorDetector.isEmulator(context)) {
          addInjector(new PersistentDataBlockServiceStub());
        }
        addInjector(new InputMethodManagerStub());
        addInjector(new MmsStub());
        addInjector(new SessionManagerStub());
        addInjector(new JobServiceStub());
        addInjector(new RestrictionStub());
      }
      addInjector(new AlarmManagerStub()); //修复超级星鱼游戏会调用Alarm来执行广播的bug
      addInjector(new AppOpsManagerStub());
      addInjector(new MediaRouterServiceStub());
      if (Build.VERSION.SDK_INT >= LOLLIPOP_MR1) {
        addInjector(new GraphicsStatsStub());
        addInjector(new UsageStatsManagerStub());
      }
      if (Build.VERSION.SDK_INT >= M) {
        addInjector(new FingerprintManagerStub());
        addInjector(new NetworkManagementStub());
      }
      if (Build.VERSION.SDK_INT >= N) {
        addInjector(new WifiScannerStub());
        if (!EmulatorDetector.isEmulator(context)) {
          addInjector(new ShortcutServiceStub());
        }
        addInjector(new DevicePolicyManagerStub());
      }
      if (Build.VERSION.SDK_INT >= 26) {
        addInjector(new AutoFillManagerStub());
      }
      VLog.i(" ====》 虚拟应用 内部framework 初始化 完成");
    }
  }

  private void addInjector(IInjector IInjector) {
    mInjectors.put(IInjector.getClass(), IInjector);
  }

  public <T extends IInjector> T findInjector(Class<T> clazz) {
    return (T) mInjectors.get(clazz);
  }

  public <T extends IInjector> void checkEnv(Class<T> clazz) {
    IInjector IInjector = findInjector(clazz);
    if (IInjector != null && IInjector.isEnvBad()) {
      try {
        IInjector.inject();
      } catch (Throwable e) {
        e.printStackTrace();
        VLog.printThrowable(e);
      }
    }
  }

  public <T extends IInjector, H extends MethodInvocationStub> H getInvocationStub(Class<T> injectorClass) {
    T injector = findInjector(injectorClass);
    if (injector != null && injector instanceof MethodInvocationProxy) {
      return (H) ((MethodInvocationProxy) injector).getInvocationStub();
    }
    return null;
  }
}